1 /*
2 Copyright: Marcelo S. N. Mancini (Hipreme|MrcSnm), 2018 - 2021
3 License:   [https://creativecommons.org/licenses/by/4.0/|CC BY-4.0 License].
4 Authors: Marcelo S. N. Mancini
5 
6 	Copyright Marcelo S. N. Mancini 2018 - 2021.
7 Distributed under the CC BY-4.0 License.
8    (See accompanying file LICENSE.txt or copy at
9 	https://creativecommons.org/licenses/by/4.0/
10 */
11 module hip.console.console;
12 import hip.config.opts;
13 import hip.util.reflection : isLiteral;
14 import hip.util.conv:to;
15 import hip.util.string : toStringz, String;
16 import hip.util.format;
17 
18 
19 enum Platforms
20 {
21     DEFAULT,
22     DESKTOP,
23     ANDROID,
24     UWP,
25     WASM,
26     PSVITA,
27     APPLEOS,
28     NULL
29 }
30 static enum androidTag = "HipremeEngine";
31 enum GUI_CONSOLE = true;
32 
33 ///If it is inside thread local storage, then, it won't work being called from another thread
34 __gshared void function(string toPrint) _log;
35 __gshared void function(string toPrint) _info;
36 __gshared void function(string toPrint) _warn;
37 __gshared void function(string toPrint) _err;
38 __gshared void function(string toPrint) _fatal;
39 version(PSVita) extern(C) void hipVitaPrint(uint length, const(char)* str);
40 
41 version(UWP){}
42 else version(Windows)
43     version = WindowsNative;
44 
45 version(WindowsNative)
46 {
47     import core.sys.windows.winbase;
48     import core.sys.windows.wincon;
49 }
50 
51 
52 enum WindowsConsoleColors
53 {
54     lightBlue = 1,
55     darkGreen = 2,
56     darkTeal = 3,
57     lightRed = 4,
58     pink = 5,
59     yellow = 6,
60     lightGrey = 7,
61     grey = 8,
62     blue = 9,
63     green = 10,
64     lightTeal = 11,
65     red = 12,
66     white = 15
67 }
68 
69 class Console
70 {
71     string name;
72     String[] lines;
73 
74     __gshared ushort idCount = 0;
75     ushort id;
76 
77     private uint logCounter = 0;
78     __gshared Console DEFAULT;
79     
80     string indentation;
81     int indentationCount;
82     int maxLines = 255;
83     int indentationSize = 4; //? Don't know if it should be used instead of \t
84     bool useTab = true;
85     bool isShowing = true;
86     
87 
88     static void install(Platforms p = Platforms.DEFAULT, void function(string) printFunc = null)
89     {
90         DEFAULT = new Console("Output", 99);
91         version(WindowsNative)
92         {
93             static void* windowsConsole;
94             if(windowsConsole is null)
95                 windowsConsole = GetStdHandle(STD_OUTPUT_HANDLE);
96         }
97         switch(p) with(Platforms)
98         {
99             case NULL:
100                 _log = function(string s){};
101                 _info = _log;
102                 _warn = _log;
103                 _err = _log;
104                 _fatal = _err;
105                 break;
106             case ANDROID:
107                 version(Android)
108                 {
109                     import hip.jni.helper.androidlog; 
110                     _log   = function(string s){alogi(androidTag, (s~"\0").ptr);};
111                     _info = _log;
112                     _warn  = function(string s){alogw(androidTag, (s~"\0").ptr);};
113                     _err   = function(string s){aloge(androidTag, (s~"\0").ptr);};
114                     _fatal = function(string s){alogf(androidTag, (s~"\0").ptr);};
115                 }
116                 break;  
117             case PSVITA:
118             {
119                 version(PSVita)
120                 {
121                     _log = function(string s){hipVitaPrint(s.length, s.ptr);};
122                     _info = _warn = _err = _fatal = _log;
123                 }
124                 break;
125             }
126             case WASM:
127                 version(WebAssembly)
128                 {
129                     import arsd.webassembly;
130                     _log = function(string s){eval(q{console.log.apply(null, arguments)}, s);};
131                     _fatal = _err = function(string s){eval(q{console.error.apply(null, arguments)}, s);};
132                     _warn = function(string s){eval(q{console.warn.apply(null, arguments)}, s);};
133                     _info = function(string s){eval(q{console.info.apply(null, arguments)}, s);};
134                 }
135                 break;
136             case UWP:
137                 _log = printFunc;
138                 _info = _log;
139                 _warn = _log;
140                 _err = _log;
141                 _fatal = _err;
142                 break;
143             case DEFAULT:
144             case APPLEOS:
145             case DESKTOP:
146             default:
147             {
148                 _log = function(string s)
149                 {
150                     version(WebAssembly) assert(false, s);
151                     else
152                     {
153                         import core.stdc.stdio;
154                         printf("%.*s\n", cast(int)s.length, s.ptr);
155                         version(PSVita){}
156                         else version(CustomRuntimeTest){}
157                         else fflush(stdout);
158                     }
159                 };
160                 _info = function(string s)
161                 {
162                     version(WindowsNative){SetConsoleTextAttribute(windowsConsole, WindowsConsoleColors.blue);}
163                     _log(s);
164                     version(WindowsNative){SetConsoleTextAttribute(windowsConsole, WindowsConsoleColors.white);}
165                 };
166                 _warn = function(string s)
167                 {
168                     version(WindowsNative){SetConsoleTextAttribute(windowsConsole, WindowsConsoleColors.yellow);}
169                     _log(s);
170                     version(WindowsNative){SetConsoleTextAttribute(windowsConsole, WindowsConsoleColors.white);}
171                 };
172                 _err = function(string s)
173                 {
174                     version(WindowsNative){SetConsoleTextAttribute(windowsConsole, WindowsConsoleColors.red);}
175                     _log(s);
176                     version(WindowsNative){SetConsoleTextAttribute(windowsConsole, WindowsConsoleColors.white);}
177                 };
178                 _fatal = function(string s)
179                 {
180                     version(WindowsNative){SetConsoleTextAttribute(windowsConsole, WindowsConsoleColors.pink);}
181                     _log(s);
182                     version(WindowsNative){SetConsoleTextAttribute(windowsConsole, WindowsConsoleColors.white);}
183                 };
184                 break;
185             }
186         }
187     }
188     private this(string consoleName, ushort id)
189     {
190         lines = new String[maxLines];
191         name = consoleName;
192         this.id = id;
193     }
194 
195     this(string consoleName)
196     {
197         lines = new String[maxLines];
198         name = consoleName;
199         id = idCount;
200         idCount++;
201     }
202 
203     private void _formatLog(ref string log)
204     {
205         log~= indentation;
206         lines[logCounter++] = log;
207         if(logCounter > maxLines)
208         {
209             lines = lines[1..$];
210             logCounter--;
211         }
212     }
213     private String formatArguments(Args...)(Args a)
214     {
215         String toLog = String(a);
216         // _formatLog(toLog);
217         return toLog;
218     }
219     
220     void hipLog(Args...)(Args a)
221     {
222         lines~= formatArguments(a);
223         _log(lines[$-1].toString);
224     }
225     
226     
227     void log(Args...)(Args a)
228     {
229         static if(!HE_NO_LOG && !HE_ERR_ONLY)
230         {
231             //mtx.lock();
232             _log(formatArguments(a).toString);
233             //mtx.unlock();
234         }
235     }
236 
237     void logStr(string str)
238     {
239         _info(str);
240     }
241     void info(Args...)(Args a)
242     {
243         static if(!HE_NO_LOG && !HE_ERR_ONLY)
244         {
245             //mtx.lock();
246             _info("INFO: " ~ formatArguments(a).toString);
247             //mtx.unlock();
248         }
249     }
250 
251     void warn(Args...)(Args a)
252     {
253         static if(!HE_NO_LOG && !HE_ERR_ONLY)
254         {
255             //mtx.lock();
256             _warn("WARNING: " ~ formatArguments(a).toString);
257             //mtx.unlock();
258         }
259     }
260     
261     void error(Args...)(Args a)
262     {
263         static if(!HE_NO_LOG)
264         {
265             //mtx.lock();
266             _err("ERROR: " ~ formatArguments(a).toString);
267             //mtx.unlock();
268         }
269     }
270   
271     void fatal(Args...)(Args a)
272     {
273         static if(!HE_NO_LOG)
274         {
275             //mtx.lock();
276             _fatal("FATAL ERROR: " ~formatArguments(a).toString);
277             //mtx.unlock();
278         }
279     }
280 
281     void indent()
282     {
283         //mtx.lock();
284         if(useTab)
285             indentation~= "\t";
286         else
287             for(int i = 0; i < indentationSize; i++)
288                 indentation~= " ";
289         indentationCount++;
290         //mtx.unlock();
291     }
292 
293     void unindent()
294     {
295         //mtx.lock();
296         if(useTab)
297             indentation = indentation[1..$];
298         else
299             indentation = indentation[indentationSize..$];
300         indentationCount--;
301         //mtx.unlock();
302     }
303 }
304 
305 void varPrint(A...)()
306 {
307     foreach(i, arg; A)
308     {
309         static if(isLiteral!(A[i]))
310         {
311         	writeln(A[i]);
312         }
313         else
314         {
315             static if(is(typeof(A[i]) == string))
316                 writeln(typeof(A[i]).stringof ~ " ", A[i].stringof, " = ", "\"", A[i], "\"");
317             else
318     		    writeln(typeof(A[i]).stringof ~ " ", A[i].stringof, " = ", A[i]);
319         }
320     }
321 }